package org.jeecg.modules.ws;

import lombok.extern.slf4j.Slf4j;

import javax.websocket.*;
import java.net.URI;
import java.net.URISyntaxException;

@Slf4j
@ClientEndpoint
public class WsClient {

    private URI uri;
    private MessageHandler messageHandler;
    private CloseHandler closeHandler;
    private ReconnectedHandler reconnectedHandler;
    private static final int maxRetryCount = 5;
    private final long maxSessionIdleTimeout = 30 * 60 * 1000L;

    public WsClient(URI endpointURI) {
        this.uri = endpointURI;
        try {
            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
            container.setDefaultMaxSessionIdleTimeout(maxSessionIdleTimeout);
            container.connectToServer(this, endpointURI);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 添加接受消息回调
     */
    public void addMessageHandler(MessageHandler msgHandler) {
        this.messageHandler = msgHandler;
    }

    /**
     * 添加连接关闭回调
     */
    public void addCloseHandler(CloseHandler closeHandler) {
        this.closeHandler = closeHandler;
    }

    /**
     * 添加重新连接回调
     */
    public void addReconnectedHandler(ReconnectedHandler reconnectedHandler) {
        this.reconnectedHandler = reconnectedHandler;
    }

    /**
     * 发送消息
     */
    public void sendMessage(String message) {
        this.userSession.setMaxTextMessageBufferSize(81920000);    //默认长度太短了，会异常
        this.userSession.getAsyncRemote().sendText(message);
    }

    /**
     * 修改 url参数用
     */
    public void setUri(URI uri) {
        this.uri = uri;
    }

    //#############################################inner###################################################

    Session userSession = null;
    private int retryCount = 0;

    @OnOpen
    public void onOpen(Session userSession) {
        System.out.println("websocket 已启动" + System.currentTimeMillis());
        userSession.setMaxIdleTimeout(maxSessionIdleTimeout);
        this.retryCount = 0;
        this.userSession = userSession;
    }

    @OnClose
    public void onClose(Session userSession, CloseReason reason) throws URISyntaxException {
        System.out.println("websocket 已关闭: " + System.currentTimeMillis() + " - " + reason.getCloseCode().getCode() + " - " + reason.getReasonPhrase());
        this.userSession = null;
        if (this.closeHandler != null) {
            boolean retry = this.closeHandler.connectClosed(reason);
            if (retry) retryConnect();
        } else retryConnect();
    }

    private void retryConnect() {
        if (retryCount < maxRetryCount) {
            try {
                Thread.sleep(1000); // 等待1秒后重试连接
                WebSocketContainer container = ContainerProvider.getWebSocketContainer();
                container.setDefaultMaxSessionIdleTimeout(maxSessionIdleTimeout);
                retryCount++;
                container.connectToServer(this, uri);
                if (this.reconnectedHandler != null) {
                    this.reconnectedHandler.reconnected();
                }
            } catch (Exception e) {
                System.out.println("重连失败（第" + retryCount + "次）: " + e.getMessage());
                retryConnect(); // 如果连接失败，继续重试连接
            }
        } else {
            System.out.println("连接次数达到上限（" + retryCount + "次）, 放弃重新连接。");
        }
    }

    @OnMessage
    public void onMessage(String message) throws Exception {
        if (this.messageHandler != null) {
            this.messageHandler.handleMessage(message);
        }
    }

    /**
     * 接受消息回调
     */
    public interface MessageHandler {
        void handleMessage(String message) throws Exception;
    }

    /**
     * 连接断开回调
     */
    public interface CloseHandler {
        /**
         * @param reason 失败原因
         * @return 是否尝试重新连接
         */
        boolean connectClosed(CloseReason reason) throws URISyntaxException;
    }

    /**
     * 重新连接回调
     */
    public interface ReconnectedHandler {
        void reconnected() throws Exception;
    }

}
